package com.cashmama.market.api.application.controller.authentication.bank;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cashmama.market.api.application.controller.authentication.AuthenticationBaseHandler;
import com.cashmama.market.api.application.controller.authentication.AuthenticationController;
import com.cashmama.market.api.application.controller.authentication.personalInfo.InputContent;
import com.cashmama.market.api.application.controller.authentication.response.UserProfileResponse;
import com.cashmama.market.api.application.controller.authentication.vos.AuthenticationContentVo;
import com.cashmama.market.api.application.controller.authentication.vos.InputParams;
import com.cashmama.market.api.application.enums.AuthenticationTypeEnum;
import com.cashmama.market.api.application.enums.ButtonTextEnum;
import com.cashmama.market.api.application.enums.ParamType;
import com.cashmama.market.api.domain.service.ApiTradeService;
import com.cashmama.market.api.domain.service.ApiUserService;
import com.cashmama.market.api.domain.service.IFSCServiceProvider;
import com.cashmama.market.api.domain.service.UserEventTrackService;
import com.cashmama.market.api.domain.vo.RequestLocalInfo;
import com.cashmama.market.api.domain.vo.user.IFSCCheckResponse;
import com.cashmama.market.api.infras.config.ApolloConfigUtil;
import com.cashmama.market.api.infras.enums.JumpRouterEnum;
import com.cashmama.market.api.infras.exception.ApplicationException;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.xjd.user.client.UserBankService;
import com.fqgj.xjd.user.client.enums.UserCardStatusEnum;
import com.fqgj.xjd.user.client.request.UserBank;
import com.fqgj.xjd.user.client.response.UserBankInfo;
import com.qianli.cashmama.trade.client.trade.TradeApplicationService;
import com.qianli.cashmama.trade.client.trade.TradeQueryService;
import com.qianli.cashmama.trade.client.trade.request.RepayTradeRequest;
import com.qianli.cashmama.trade.client.trade.request.UserTradeListQueryRO;
import com.qianli.cashmama.trade.client.trade.response.TradeInfoRO;
import com.qianli.cashmama.trade.common.enums.TradeStatusEnum;
import com.qianli.user.enums.UserAuthEnum;
import com.qianli.user.enums.UserAuthStatusEnum;
import com.qianli.user.ro.auth.UserAuthStatusRO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 * User: yujianfu (mr.vencnet@gmail.com)
 * Date: 2019-12-23
 * Time: 09:56
 */
@Service
public class BankAuthenticationHandler extends AuthenticationBaseHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(BankAuthenticationHandler.class);

    @Autowired
    private UserBankService userBankService;
    @Autowired
    private TradeQueryService tradeQueryService;
    @Autowired
    private TradeApplicationService tradeApplicationService;
    @Autowired
    private IFSCServiceProvider ifscServiceProvider;
    @Autowired
    private ApiUserService apiUserService;
    @Autowired
    private ApiTradeService apiTradeService;
    @Autowired
    private ApolloConfigUtil apolloConfigUtil;
    @Autowired
    private UserEventTrackService userEventTrackService;

    @PostConstruct
    public void init() {
        AuthenticationController.authenticationBaseHandlerMap.put(AuthenticationTypeEnum.BANK.getType(), this);
    }

    @Override
    public AuthenticationContentVo content() {
        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        BankInfo bankInfo = new BankInfo();
        /*try {
            Response<UserBankInfo> response = userBankService.getByUserCode(userCode);
            UserBankInfo userBankInfo = response.getData();
            if(userBankInfo != null){
                BankEnum bankEnum = BankEnum.getBankEnumByDesc(userBankInfo.getName());
                LOGGER.info("======== userBankInfo:{},bankEnum:{} =========", JSONObject.toJSONString(userBankInfo), bankEnum);
                bankInfo.setBankName(new InputParams().setInputValue(String.valueOf(bankEnum.getType())));
                bankInfo.setIfsCode(new InputParams().setInputValue(userBankInfo.getCode()));
                bankInfo.setBankAccountNo(new InputParams().setInputValue(userBankInfo.getCardNo()));
                bankInfo.setReEnterBankAccountNo(new InputParams().setInputValue(userBankInfo.getCardNo()));
            }
        } catch (Exception e) {
            LOGGER.error("================== get bank info error:{} ==================", e);
        }*/
        AuthenticationContentVo authenticationContentVo = explain(bankInfo);
        authenticationContentVo.setButtonText(ButtonTextEnum.CONFIRM.getText());
        authenticationContentVo.setButtonVisibility(true);
        return authenticationContentVo;
    }

    @Override
    public UserProfileResponse save(Map<String, String> inputParams) {
        LOGGER.info("inputParams:{}", JSONObject.toJSONString(inputParams));
        BankInfo bankInfo = new BankInfo();
        getObject(bankInfo, inputParams);
        LOGGER.info("bankInfo:{}", JSONObject.toJSONString(bankInfo));
        doSave(bankInfo);
        UserProfileResponse userProfileResponse = new UserProfileResponse()
                .setJumpUrl(this.getJumperUrl());
        return userProfileResponse;
    }

    private class BankInfo {

        @InputContent(paramName = "IFSC Code", param = "ifsCode", inputDesc = "Enter IFSC Code", paramType = ParamType.TEXT)
        private InputParams ifsCode;

        @InputContent(paramName = "Bank Name", param = "bankName", paramType = ParamType.TEXT)
        private InputParams bankName;

        @InputContent(paramName = "Bank Account No.", param = "bankAccountNo", inputDesc = "Enter Bank Account No.", paramType = ParamType.TEXT)
        private InputParams bankAccountNo;

        @InputContent(paramName = "Re-enter Bank Account No.", param = "reEnterBankAccountNo", inputDesc = "Re-enter Enter Bank Account No.", paramType = ParamType.TEXT)
        private InputParams reEnterBankAccountNo;

        public InputParams getBankName() {
            return bankName;
        }

        public BankInfo setBankName(InputParams bankName) {
            this.bankName = bankName;
            return this;
        }

        public InputParams getBankAccountNo() {
            return bankAccountNo;
        }

        public BankInfo setBankAccountNo(InputParams bankAccountNo) {
            this.bankAccountNo = bankAccountNo;
            return this;
        }

        public InputParams getReEnterBankAccountNo() {
            return reEnterBankAccountNo;
        }

        public BankInfo setReEnterBankAccountNo(InputParams reEnterBankAccountNo) {
            this.reEnterBankAccountNo = reEnterBankAccountNo;
            return this;
        }

        public InputParams getIfsCode() {
            return ifsCode;
        }

        public BankInfo setIfsCode(InputParams ifsCode) {
            this.ifsCode = ifsCode;
            return this;
        }
    }

    private void doSave(BankInfo bankInfo) {
        if (StringUtils.isBlank(bankInfo.getIfsCode().getInputValue())
                || StringUtils.isBlank(bankInfo.getBankName().getInputValue())
                || StringUtils.isBlank(bankInfo.getBankAccountNo().getInputValue())
                || StringUtils.isBlank(bankInfo.getReEnterBankAccountNo().getInputValue())) {
            throw new ApplicationException("Parameter validation failed");
        }

        this.validateBankAccountNumber(bankInfo.getBankAccountNo().getInputValue().replaceAll("\\s*", ""));
        //不支持YesBank
        if (!apolloConfigUtil.permitYesBankBind() && bankInfo.getIfsCode().getInputValue().toUpperCase().startsWith("YESB")) {
            throw new ApplicationException("YesBank is not supported, please use other banks");
        }
        IFSCCheckResponse ifscCheckResponse = ifscServiceProvider.ifscCheck(bankInfo.getIfsCode().getInputValue().trim().replaceAll("\\s*", ""));
        if (!ifscCheckResponse.isCheckSuccess() || StringUtils.isEmpty(ifscCheckResponse.getBank())) {
            throw new ApplicationException("IFSC code is invalid");
        }
        if (!Objects.equals(bankInfo.getReEnterBankAccountNo().getInputValue().replaceAll("\\s*", ""), bankInfo.getBankAccountNo().getInputValue().replaceAll("\\s*", ""))) {
            throw new ApplicationException("Bank Account No is inconsistent with the Re-enter Bank Account No");
        }

        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        String ifscCode = bankInfo.getIfsCode().getInputValue().replaceAll("\\s*", "");
        String bankAccount = bankInfo.getBankAccountNo().getInputValue().replaceAll("\\s*", "");
        //用户之前银行卡状态
        UserBankInfo userBankInfo = userBankService.getByUserCode(userCode).getData();
        if(userBankInfo != null && userBankInfo.getCardNo().equalsIgnoreCase(bankAccount)){
            throw new ApplicationException("The current bank account has been bound, please bind another bank account");
        }

        this.bankRebind(userCode, ifscCode, bankAccount, ifscCheckResponse.getBank());

        UserBank userBank = new UserBank();
        userBank.setUserCode(userCode);
        userBank.setCode(ifscCode);
        userBank.setNumber(bankAccount);
        userBank.setName(ifscCheckResponse.getBank());
        userBank.setUserCardStatusEnum(UserCardStatusEnum.CHECK_SUCCESS);
        userBankService.bind(userBank);
        apiUserService.updateUserAuthStatus(UserAuthStatusEnum.SUCCESS, UserAuthEnum.BANK_STATUS, RequestLocalInfo.getCurrentUser().getUserCode());
        userEventTrackService.e_app_submit_information_done();
        userEventTrackService.e_app_bind_bankcard_done();
    }

    private void validateBankAccountNumber(String bankAccountNumber) {
        String check = "^\\d{9,18}$";
        Pattern regex = Pattern.compile(check);
        Matcher matcher = regex.matcher(bankAccountNumber);
        if (!matcher.matches()) {
            throw new ApplicationException("Please enter the correct pure numeric Bank Account Number");
        }
    }

    /**
     * 重绑卡逻辑
     *
     * @param userCode
     */
    private void bankRebind(String userCode, String ifscCode, String cardNumber, String bankName) {
        UserTradeListQueryRO userTradeListQueryRO = new UserTradeListQueryRO();
        userTradeListQueryRO.setNeedCardInfo(false);
        userTradeListQueryRO.setUserCode(userCode);
        userTradeListQueryRO.setOrderStatus(TradeStatusEnum.PAY_RETRY.getStatus());
        Response<List<TradeInfoRO>> listResponse = tradeQueryService.queryTradeListByUserCodeAndOrderStatus(userTradeListQueryRO);
        LOGGER.info("==进入重绑卡,查询交易==,userCode:{},response:{}", userCode, JSON.toJSONString(listResponse));
        if (listResponse.isSuccess() && CollectionUtils.isNotEmpty(listResponse.getData())) {
            List<TradeInfoRO> tradeInfos = listResponse.getData();
            tradeInfos.forEach(s->{
                if (TradeStatusEnum.PAY_RETRY.getStatus() == s.getOrderStatus().getStatus()) {
                    RepayTradeRequest tradeRequest = new RepayTradeRequest()
                            .setTradeNo(s.getTradeNo())
                            .setBankName(bankName)
                            .setBankType(ifscCode)
                            .setCardNo(cardNumber)
                            .setUserCode(userCode);
                    LOGGER.info("==进入重绑卡,推送给交易==,userCode:{},userBankInfo:{}", userCode, JSON.toJSONString(tradeRequest));
                    Response response = tradeApplicationService.updateBankInfoAndLoanMarket(tradeRequest);
                    LOGGER.info("==进入重绑卡,推送给交易结果==,userCode:{},response:{}", userCode, JSON.toJSONString(response));
                }
            });
        }
        LOGGER.info("重绑卡处理完成,userCode:{}", userCode);
    }

    private String getJumperUrl() {
        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        UserAuthStatusRO userAuthStatusRO = apiUserService.getUserAuthStatus(userCode);
        boolean kycComplete = apiUserService.kycActionComplete(userAuthStatusRO);
        boolean workComplete = userAuthStatusRO.getBaseWorkStatus() == UserAuthStatusEnum.SUCCESS.getCode();
        if (!kycComplete) {
            return JumpRouterEnum.KYC_DOCUMENTS_AADHAAR.getJumpUrl();
        } else if (kycComplete && !workComplete) {
            return JumpRouterEnum.PERSONAL_INFO_EMPLOYEE.getJumpUrl();
        } else {
            return JumpRouterEnum.HOME.getJumpUrl();
        }
    }
}
